package com.miku.project.controller;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.miku.mikuapicommon.model.entity.ProductInfo;
import com.miku.mikuapicommon.model.entity.ProductOrder;
import com.miku.project.annotation.AuthCheck;
import com.miku.project.common.BaseResponse;
import com.miku.project.common.ErrorCode;
import com.miku.project.common.ResultUtils;
import com.miku.project.exception.BusinessException;
import com.miku.project.model.dto.order.PayCreateRequest;
import com.miku.project.model.dto.productorder.ProductOrderQueryRequest;
import com.miku.project.model.enums.PaymentStatusEnum;
import com.miku.project.model.vo.OrderVo;
import com.miku.project.model.vo.ProductOrderVo;
import com.miku.project.model.vo.UserVO;
import com.miku.project.service.OrderService;
import com.miku.project.service.ProductOrderService;
import com.miku.project.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.miku.project.constant.PayConstant.QUERY_ORDER_STATUS;
import static com.miku.project.model.enums.PaymentStatusEnum.SUCCESS;

/**
 * 订单接口
 */
@RestController
@RequestMapping("/order")
@Api(tags = "订单接口")
public class OrderController {

    @Resource
    private RedisTemplate<String, Boolean> redisTemplate;

    @Resource
    private UserService userService;
    @Resource
    private OrderService orderService;
    @Resource
    private ProductOrderService productOrderService;

    /**
     * 创建订单
     *
     * @param payCreateRequest
     * @param request
     * @return
     */
    @PostMapping("/create")
    @ApiOperation("创建订单")
    public BaseResponse<ProductOrderVo> createOrder(@RequestBody PayCreateRequest payCreateRequest, HttpServletRequest request) {
        if (ObjectUtils.anyNull(payCreateRequest) || StringUtils.isBlank(payCreateRequest.getProductId())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //接口
        Long productId = Long.valueOf(payCreateRequest.getProductId());
        String payType = payCreateRequest.getPayType();
        if (StringUtils.isBlank(payType)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "支付类型不能为空");
        }
        UserVO loginUser = userService.getLoginUser(request);
        ProductOrderVo productOrderVo = orderService.createOrderByPayType(productId, payType, loginUser);
        if (productOrderVo == null) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "订单创建失败，请稍后再试");
        }
        return ResultUtils.success(productOrderVo);
    }


    /**
     * 删除订单
     *
     * @param id
     * @param request
     * @return
     */
    @PostMapping("/delete")
    @ApiOperation("删除订单")
    public BaseResponse<Boolean> deleteProductOrder(String id, HttpServletRequest request) {
        if (StringUtils.isBlank(id)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "id不能为空");
        }
        UserVO loginUser = userService.getLoginUser(request);
        //校验数据是否存在
        ProductOrder productOrder = productOrderService.getById(id);
        if (productOrder == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "订单不存在");
        }
        //仅本人或者管理员可以删除
        if (!productOrder.getUserId().equals(loginUser.getId()) || !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有权限删除");
        }
        return ResultUtils.success(productOrderService.removeById(id));
    }

    @GetMapping("/get")
    @ApiOperation("根据id获取订单")
    public BaseResponse<ProductOrderVo> getProductOrderById(String id) {
        if (StringUtils.isBlank(id)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "id不能为空");
        }

        ProductOrder productOrder = productOrderService.getById(id);
        if (productOrder == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "订单不存在");
        }
        ProductOrderVo productOrderVo = formatProductOrderVo(productOrder);
        return ResultUtils.success(productOrderVo);
    }


    /**
     * 分页获取订单列表
     * @param orderQueryRequest
     * @param request
     * @return
     */
    @GetMapping("/list/page")
    @ApiOperation("分页获取订单列表")
    public BaseResponse<OrderVo> listProductOrderByPage(ProductOrderQueryRequest orderQueryRequest, HttpServletRequest request){
        if (orderQueryRequest == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"请求参数为空");
        }
        ProductOrder productOrder = new ProductOrder();
        BeanUtils.copyProperties(orderQueryRequest,productOrder);
        String orderName = orderQueryRequest.getOrderName();
        String orderNo = orderQueryRequest.getOrderNo();
        Integer total = orderQueryRequest.getTotal();
        String status = orderQueryRequest.getStatus();
        String payType = orderQueryRequest.getPayType();
        String productInfo = orderQueryRequest.getProductInfo();
        Integer addPoints = orderQueryRequest.getAddPoints();
        long current = orderQueryRequest.getCurrent();
        long pageSize = orderQueryRequest.getPageSize();
        String sortField = orderQueryRequest.getSortField();
        String sortOrder = orderQueryRequest.getSortOrder();
        //限制爬虫
        if (pageSize>50){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"invalid pageSize");
        }
        UserVO loginUser = userService.getLoginUser(request);
        QueryWrapper<ProductOrder> queryWrapper = new QueryWrapper<>();
        //分页查询
        queryWrapper.like(StringUtils.isNotBlank(orderName),"orderName",orderName)
                .like(StringUtils.isNotBlank(productInfo),"productInfo",productInfo)
                .eq("userId",loginUser.getId())
                .eq(StringUtils.isNotBlank(orderNo),"orderNo",orderNo)
                .eq(StringUtils.isNotBlank(status),"status",status)
                .eq(StringUtils.isNotBlank(payType),"payType",payType)
                .eq(ObjectUtils.isNotEmpty(addPoints),"addPoints",addPoints)
                .eq(ObjectUtils.isNotEmpty(total),"total",total);
        //未支付的订单前置
        queryWrapper.last("ORDER BY CASE WHEN status='NOTPAY' THEN 0 ELSE 1 END,status");
        Page<ProductOrder> page = productOrderService.page(new Page<>(current, pageSize), queryWrapper);
        OrderVo orderVo = new OrderVo();
        BeanUtils.copyProperties(page,orderVo);
        //处理订单信息
        List<ProductOrderVo> orderVos = page.getRecords().stream().map(this::formatProductOrderVo).collect(Collectors.toList());
        orderVo.setRecords(orderVos);
        return ResultUtils.success(orderVo);
    }


    /**
     * 查询订单状态
     * @param productOrderQueryRequest
     * @return
     */
    @PostMapping("/query/status")
    @ApiOperation("查询订单状态")
    public BaseResponse<Boolean> queryOrderStatus(@RequestBody ProductOrderQueryRequest productOrderQueryRequest){
        if (ObjectUtils.isEmpty(productOrderQueryRequest) || StringUtils.isBlank(productOrderQueryRequest.getOrderNo())){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String orderNo = productOrderQueryRequest.getOrderNo();
        //查询缓存
        Boolean data = redisTemplate.opsForValue().get(QUERY_ORDER_STATUS + orderNo);
        if (Boolean.TRUE.equals(data)){
            return ResultUtils.success(data);
        }
        ProductOrder productOrder=productOrderService.getProductOrderByOutTradeNo(orderNo);
        if (SUCCESS.getValue().equals(productOrder.getStatus())){
            return ResultUtils.success(true);
        }
        //查询失败,存入缓存
        redisTemplate.opsForValue().set(QUERY_ORDER_STATUS+orderNo,false,10, TimeUnit.MINUTES);

        return ResultUtils.success(false);
    }

    /**
     * 取消订单
     * @param orderNo
     * @return
     */
    @PostMapping("/closed")
    @ApiOperation("取消订单")
    public BaseResponse<Boolean> closedProductOrder(String orderNo){
        if (StringUtils.isBlank(orderNo)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"订单号不能为空");
        }
        //判断是否存在
        ProductOrder tradeNo = productOrderService.getProductOrderByOutTradeNo(orderNo);
        if (tradeNo==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"订单不存在");
        }
        ProductOrderService orderServiceByPayType=orderService.getProductOrderServiceByPayType(tradeNo.getPayType());
        boolean closedResult=orderServiceByPayType.updateOrderStatusByOrderNo(orderNo, PaymentStatusEnum.CLOSED.getValue());
        return ResultUtils.success(closedResult);
    }

    /**
     * 解析订单通知结果
     * @param notifyDate
     * @param request
     * @return
     */
    @PostMapping("/notify/order")
    @ApiOperation("解析订单通知结果")
    public String parseOrderNotifyResult(@RequestBody String notifyDate,HttpServletRequest request){
        return orderService.doOrderNotify(notifyDate,request);
    }

    /**
     * 封装返回
     *
     * @param productOrder
     * @return
     */
    private ProductOrderVo formatProductOrderVo(ProductOrder productOrder) {
        ProductOrderVo productOrderVo = new ProductOrderVo();
        BeanUtils.copyProperties(productOrder, productOrderVo);
        ProductInfo productInfo = JSONUtil.toBean(productOrder.getProductInfo(), ProductInfo.class);
        productOrderVo.setDescription(productInfo.getDescription());
        productOrderVo.setProductType(productInfo.getProductType());
        String voTotal = String.valueOf(productInfo.getTotal());
        BigDecimal total = new BigDecimal(voTotal).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
        productOrderVo.setTotal(total.toString());
        return productOrderVo;
    }
}
